"""
首页管理
"""

import threading

import openstack
from flask import current_app
from flask_restx import abort
from sqlalchemy import and_, or_
from app.common.zstack_manager import ZStackManager
from app.api.v1.organizer.rangeEnv import RangeBase
from app.models import (
    Image,
    courseModel,
    coursewareModel,
    ctfModel,
    questionModel,
    rangeModel,
    roleModel,
    userModel, classesModel,
)
from app.models.rangeModel import Range
from tools import cache, db
from utils.crypto import decrypt_pw


class HomeBase(RangeBase):
    def __init__(self, api=None, *args, **kwargs):
        super().__init__(api=api, *args, **kwargs)
        # Initialize cloud
        # 获取当前用户信息
        """
        根据客户定制配置虚拟化参数
        """
        openstackAuthConfig = decrypt_pw(current_app.config["OPENSTACK"]["auth"])
        openstackAuthConfig["project_id"] = self.user.project_id

        try:
            self.conn = openstack.connect(
                auth=openstackAuthConfig,
                auth_type=current_app.config["OPENSTACK"]["auth_type"],
            )
        except Exception as e:
            current_app.logger.exception(e)
            abort(500, message="无法连接到云计算服务")

    # 红蓝靶场统计
    def get_red_blue_count(self):
        self.red_blue_count = ctfModel.CtfRedBlue.query.filter(
            ctfModel.CtfRedBlue.create_user_id == self.user.id
        ).count()

    # CTF统计
    def get_ctf_count(self):
        self.ctf_count = ctfModel.Ctf.query.filter(
            ctfModel.Ctf.user_id == self.user.id
        ).count()

    # CTF题库统计
    def get_ctf_question(self):
        self.ctf_question_count = questionModel.CtfQuestion.query.filter(
            or_(
                questionModel.CtfQuestion.belong.in_(
                    [
                        questionModel.CtfIssueBelong.system,
                        questionModel.CtfIssueBelong.system_bind_vm,
                    ]
                ),
                and_(
                    questionModel.CtfQuestion.belong.in_(
                        [
                            questionModel.CtfIssueBelong.user_upload,
                            questionModel.CtfIssueBelong.user_bind_vm,
                        ]
                    ),
                    questionModel.CtfQuestion.user_id == 1,
                ),
            ),
            questionModel.CtfQuestion.user_id == self.user.id,
        ).count()

    # 仿真场景统计
    def get_range_count(self):
        self.range_count = rangeModel.Range.query.filter_by(
            is_system=False, user_id=self.user.id
        ).count()

    # 课件统计
    def get_courseware_count(self):
        self.courseware_count = coursewareModel.Courseware.query.filter(
            coursewareModel.Courseware.user_id == self.user.id
        ).count()

    # 课程统计
    def get_course_count(self):
        self.course_count = courseModel.Course.query.filter(
            courseModel.Course.user_id == self.user.id
        ).count()

    # 用户统计
    def get_user_count(self):
        self.user_count = (
            userModel.User.query.join(
                roleModel.Role,
                roleModel.Role.name == roleModel.PresetRoleChoices.student.value,
            )
            .join(
                roleModel.UserRole,
                and_(
                    roleModel.UserRole.user_id == userModel.User.id,
                    roleModel.UserRole.role_id == roleModel.Role.id,
                ),
            )
            .count()
        )

    def get_user_info(self):
        """获取用户信息"""
        self.user_info = {}
        self.user_info.update({"teacher": userModel.User.query.filter_by(role_id=1).count()})
        self.user_info.update({"student": userModel.User.query.filter_by(role_id=0).count()})
        self.user_info.update({"team": ctfModel.CtfRedBlueGroup.query.count() // 2})
        self.user_info.update({"classes": classesModel.Classes.query.count()})
        self.user_info.update({"red_team": ctfModel.CtfRedBlueGroup.query.filter_by(group_type="red").count()})
        self.user_info.update({"blue_team": ctfModel.CtfRedBlueGroup.query.filter_by(group_type="blue").count()})
        self.user_info.update({"other": (ctfModel.CtfRedBlue.query.count()) + (ctfModel.Ctf.query.count())})

    def get_course_total(self):
        """获取课程统计"""
        self.course_total = {}
        industrial_control = courseModel.Course.query.filter(courseModel.Course.user_id == self.user.id,
                                                             courseModel.Course.name.contains("工控安全")).count()
        net_safety = courseModel.Course.query.filter(courseModel.Course.user_id == self.user.id,
                                                     courseModel.Course.name.contains("网络安全")).count()
        industrial_automation = courseModel.Course.query.filter(courseModel.Course.user_id == self.user.id,
                                                                courseModel.Course.name.contains("工业自动化")).count()
        self.course_total.update({"industrial_control": industrial_control, "net_safety": net_safety,
                                  "industrial_automation": industrial_automation,
                                  "total": industrial_control + net_safety + industrial_automation})

    def get_vm_max_rate(self):
        self.vm_max_rate = self.conn.compute.get_limits()["absolute"].toDict()

    def get_vm_list(self):
        self.rangVmList = (
            rangeModel.RangeVm.query.filter_by(user_id=self.user.id)
            .order_by(rangeModel.RangeVm.update_time.desc())
            .limit(10)
            .all()
        )

    def get_ctf_date(self):
        from sqlalchemy.sql import func

        ctf_status = (
            ctfModel.Ctf.query.with_entities(
                func.count(ctfModel.Ctf.id).label("countID"),
                func.FROM_UNIXTIME((ctfModel.Ctf.start_date), "%Y-%m-%d").label(
                    "weeks"
                ),
            )
            .filter(ctfModel.Ctf.user_id == self.user.id)
            .group_by("weeks")
            .all()
        )
        self.ctf_count_num = {}
        for status in ctf_status:
            self.ctf_count_num[status[1]] = status[0]

    def get_ctf_working(self):
        from sqlalchemy.sql import func

        ctf_status = (
            ctfModel.Ctf.query.with_entities(
                func.count(ctfModel.Ctf.id), ctfModel.Ctf.status
            )
            .filter(ctfModel.Ctf.user_id == self.user.id)
            .group_by(ctfModel.Ctf.status)
            .all()
        )

        # "ctf_status": {
        #     "close": self.ctf_status[0],
        #     "starting": self.ctf_status[1],
        #     "finish": self.ctf_status[2]
        # },
        self.ctf_status = {"close": 0, "starting": 0, "finish": 0}
        for status in ctf_status:
            if status[1] == 0:
                self.ctf_status["close"] = status[0]
            if status[1] == 1:
                self.ctf_status["starting"] = status[0]
            if status[1] == 2:
                self.ctf_status["finish"] = status[0]

    def get_red_blue_date(self):
        from sqlalchemy.sql import func

        red_blue_status = (
            ctfModel.CtfRedBlue.query.with_entities(
                func.count(ctfModel.CtfRedBlue.id).label("countID"),
                func.FROM_UNIXTIME((ctfModel.CtfRedBlue.start_date), "%Y-%m-%d").label(
                    "weeks"
                ),
            )
            .filter(ctfModel.CtfRedBlue.create_user_id == self.user.id)
            .group_by("weeks")
            .all()
        )
        self.red_blue_count_num = {}
        for status in red_blue_status:
            self.red_blue_count_num[status[1]] = status[0]

    def get_red_blue_working(self):
        from sqlalchemy.sql import func

        red_blue_status = (
            ctfModel.CtfRedBlue.query.with_entities(
                func.count(ctfModel.CtfRedBlue.id), ctfModel.CtfRedBlue.status
            )
            .filter(ctfModel.CtfRedBlue.create_user_id == self.user.id)
            .group_by(ctfModel.CtfRedBlue.status)
            .all()
        )

        self.red_blue_status = {"close": 0, "starting": 0, "finish": 0}
        for status in red_blue_status:
            if status[1] == 0:
                self.red_blue_status["close"] = status[0]
            if status[1] == 1:
                self.red_blue_status["starting"] = status[0]
            if status[1] == 2:
                self.red_blue_status["finish"] = status[0]

    def get_images_count(self):
        image_infos = Image.query.all()

        self.images_count = {
            "images_count": len(image_infos),
            "smz": 0,
            "ab": 0,
            "snd": 0,
            "wincc": 0,
        }

        for image in image_infos:  # noqa
            try:
                type = image.image_type.split("-")
                if type[0] == "plc":
                    self.images_count[type[1]] += 1
                if type[0] == "wincc":
                    self.images_count["wincc"] += 1
            except:  # noqa
                continue


class HomeIndex(HomeBase):
    # @20220927临时修改测试环境首页缓存时间为30秒
    @cache.cached(timeout=30)
    def post(self):

        t1 = threading.Thread(target=self.get_vm_max_rate())
        t2 = threading.Thread(target=self.get_vm_list())
        t3 = threading.Thread(target=self.get_red_blue_count())
        t3_1 = threading.Thread(target=self.get_ctf_count())
        t4 = threading.Thread(target=self.get_ctf_question())
        t5 = threading.Thread(target=self.get_range_count())
        t6 = threading.Thread(target=self.get_courseware_count())
        t7 = threading.Thread(target=self.get_course_count())
        t8 = threading.Thread(target=self.get_user_count())
        t9 = threading.Thread(target=self.get_red_blue_working())
        t10 = threading.Thread(target=self.get_images_count())
        t11 = threading.Thread(target=self.get_red_blue_date())

        t12 = threading.Thread(target=self.get_ctf_working())
        t13 = threading.Thread(target=self.get_ctf_date())
        t14 = threading.Thread(target=self.get_user_info())
        t15 = threading.Thread(target=self.get_course_total())
        t1.start()
        t2.start()
        t3.start()
        t3_1.start()
        t4.start()
        t5.start()
        t6.start()
        t7.start()
        t8.start()
        t9.start()
        t10.start()
        t11.start()
        t12.start()
        t13.start()
        t14.start()
        t15.start()

        zstack_manager = ZStackManager()
        limits = zstack_manager.get_vm_max_rate_info()

        vm_list = []
        for _ in self.rangVmList:
            vm_list.append(
                {
                    "vm_name": _.vm_name,
                    "create_time": _.create_time.strftime("%Y-%m-%d %H:%M:%S"),
                    "type": _.type,
                }
            )

        # 整合日期
        for item in set(self.red_blue_count_num.keys()) ^ set(
                self.ctf_count_num.keys()
        ):
            self.red_blue_count_num.setdefault(item, 0)
            self.ctf_count_num.setdefault(item, 0)

        all_ctf, all_rb_ctf = sum(self.ctf_count_num.values()), sum(
            self.red_blue_count_num.values()
        )

        data = {
            "max_rate": limits,
            "vm_list": vm_list,
            "red_blue_status": {
                key: val / all_rb_ctf if all_rb_ctf else 0
                for key, val in self.red_blue_status.items()
            },
            "red_blue_count_num": dict(sorted(self.red_blue_count_num.items(), key=lambda x: x[0], reverse=True)),
            "ctf_status": {
                key: val / all_ctf if all_ctf else 0
                for key, val in self.ctf_status.items()
            },
            "ctf_count_num": self.ctf_count_num,
            "images_count": self.images_count,
            "user_info": self.user_info,
            "course_total": self.course_total,
            "business_data": {
                "red_blue_count": self.red_blue_count,
                "range_count": self.range_count,
                "user_count": self.user_count,
                "ctf_count": self.ctf_count,
                "ctf_question_count": self.ctf_question_count,
                "course_count": self.course_count,
                "courseware_count": self.courseware_count,
            },
        }

        return {"code": 200, "data": data}


class HomeRangeInfo(HomeBase):
    control_type = [
        "plc-smz",
        "plc-ab",
        "plc-snd",
        "plc-other",
        "wincc",
        "mis",
        "sis",
        "ifix",
        "sensor",
    ]
    other_type = ["vpn", "router"]

    def get(self):
        range_list = Range.query.filter(
            Range.is_system == 0,
            Range.range_template_type != "",
            Range.user_id == self.user.id,
        ).all()

        range_info = {
            item.name: {
                "range_type_name": item.label,
                "count": 0,
                "vm_count": 0,
                "control_count": 0,
                "net_count": 0,
            }  # noqa
            for item in Range.RangeTemplate
        }

        for _range in range_list:
            range_info[_range.range_template_type]["count"] += 1

            for vm in _range.Range[0].vmList:
                if vm.type in self.control_type:
                    range_info[_range.range_template_type]["control_count"] += 1
                elif vm.type not in self.other_type:
                    range_info[_range.range_template_type]["vm_count"] += 1

            range_uuid = _range.Range[0].range_uuid
            range_info[_range.range_template_type]["net_count"] = db.session.execute(
                f"""
                    SELECT
                        count( * )
                    FROM (
                        SELECT subnet_id AS unique_id FROM api_switch
                        WHERE range_uuid = '{range_uuid}' UNION
                        SELECT op_route AS unique_id FROM api_route
                        WHERE range_uuid = '{range_uuid}' UNION
                        SELECT vpnserver_id AS unique_id FROM api_vpn
                        WHERE range_uuid = '{range_uuid}'
                    ) as a
                """
            ).scalar()

        return [{**info, "type": _type} for _type, info in range_info.items()]
